﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Text.RegularExpressions;
using WMM.Tapioca.Instance;
using WMM.Tapioca.Taxonomy;

namespace WMM.Tapioca.Formula.Filters
{
    /// <summary>
    /// The concept substitution-group filter can be used to match facts based
    /// on its XML Schema substitution group.
    /// </summary>
    public class ConceptSubstitutionGroupFilter : Filter
    {
        private bool strict;

        /// <returns> When strict="false" allow to compare with item derived from substitutionGroup="xbrli:item". </returns>
        public bool Strict
        {
            get { return strict; }
            set { strict = value; }
        }

        private string substitutionGroup;

        /// <returns> The @substitutionGroup attribute that the fact's concept must match. </returns>
        public string SubstitutionGroup
        {
            get { return substitutionGroup; }
            set { substitutionGroup = value; }
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        public ConceptSubstitutionGroupFilter(Linkbase.Resource resource)
            : base(resource)
        {
            strict = Boolean.Parse((string)resource.ResourceXElement.Attribute("strict") ?? string.Empty);

            XElement qnameX = resource.ResourceXElement.Descendants().Where(d => d.Name.LocalName.Equals("qname")).FirstOrDefault();

            if (qnameX != null)
            {
                string qname = qnameX.Value;
                qname = qname.TrimEnd().TrimStart();
                qname = Regex.Replace(qname, @"\s+", " ");
                substitutionGroup = qname;
            }

            XElement qnameExpression = resource.ResourceXElement.Descendants().Where(d => d.Name.LocalName.Equals("qnameExpression")).FirstOrDefault();

            if (qnameExpression != null)
            {
                string expression = qnameExpression.Value;
                expression = expression.TrimEnd().TrimStart();
                expression = Regex.Replace(expression, @"\s+", " ");
                substitutionGroup = EvaluateExpression(expression);
            }
        }


        public override List<FactItem> EvaluateFilter(VariableSet variableSet, List<FactItem> itemsToFilter, DTS dts)
        {
            this.dts = dts;

            List<FactItem> itemListTemp = new List<FactItem>();

            foreach (FactItem item in itemsToFilter)
            {
                string substitutionGroup = SubstitutionGroup.Substring(SubstitutionGroup.IndexOf(':') + 1);

                if (Strict)
                {
                    if (Complement ? !item.Concept.SchemaElement.SubstitutionGroup.Name.Equals(substitutionGroup) :
                        item.Concept.SchemaElement.SubstitutionGroup.Name.Equals(substitutionGroup))
                    {
                        itemListTemp.Add(item);
                    }
                }
                else
                {
                    if (item.Concept.SchemaElement.SubstitutionGroup.Name == "item" || item.Concept.SchemaElement.SubstitutionGroup.Name == "tuple")
                    {
                        if (Complement ? !(item.Concept.SchemaElement.SubstitutionGroup.Name.Equals(substitutionGroup)) :
                            item.Concept.SchemaElement.SubstitutionGroup.Name.Equals(substitutionGroup))
                        {
                            itemListTemp.Add(item);
                        }
                    }
                    else
                    {
                        Concept conceptSG = dts.GetConceptByName(item.Concept.SchemaElement.SubstitutionGroup.Name);

                        if (conceptSG != null)
                        {
                            if (Complement ? !(conceptSG.SchemaElement.SubstitutionGroup.Name.Equals(substitutionGroup)) :
                                conceptSG.SchemaElement.SubstitutionGroup.Name.Equals(substitutionGroup))
                            {
                                itemListTemp.Add(item);
                            }
                        }
                    }
                }
            }

            return itemListTemp;
        }
    }
}
